home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
FSTR.C
< prev
next >
Wrap
Text File
|
1990-03-02
|
18KB
|
745 lines
/*
* File: fstr.c
* Contents: center, detab, entab, left, map, repl, reverse, right, trim
*/
#include "::h:config.h"
#include "::h:rt.h"
#include "rproto.h"
#include <ctype.h>
/*
* Prototype.
*/
hidden int nxttab Params((int col));
#ifdef PreProcess
/* include(../M4/fncs.m4) /* */
/* */
#endif /* PreProcess */
/*
* center(s1,n,s2) - pad s1 on left and right with s2 to length n.
*/
FncDcl(center,3)
{
register char *s, *st;
word cnt, slen, hcnt;
char *sbuf, *s3;
char sbuf1[MaxCvtLen], sbuf2[MaxCvtLen];
/*
* Arg1 must be a string. Arg2 must be a non-negative integer and defaults
* to 1. Arg3 must be a string and defaults to a blank.
*/
if (cvstr(&Arg1, sbuf1) == CvtFail)
RunErr(103, &Arg1);
if (defshort(&Arg2, 1) == Error)
RunErr(0, NULL);
if ((cnt = IntVal(Arg2)) < 0)
RunErr(205, &Arg2);
if (defstr(&Arg3, sbuf2, &blank) == Error)
RunErr(0, NULL);
if (strreq(cnt) == Error)
RunErr(0, NULL);
if (StrLen(Arg3) == 0) {
/*
* The padding string is null; make it a blank.
*/
slen = 1;
s3 = " ";
}
else {
slen = StrLen(Arg3);
s3 = StrLoc(Arg3);
}
/*
* Get space for the new string. Start at the right
* of the new string and copy Arg3 into it from right to left as
* many times as will fit in the right half of the new string.
*/
sbuf = alcstr(NULL, cnt);
hcnt = cnt / 2;
s = sbuf + cnt;
while (s > sbuf + hcnt) {
st = s3 + slen;
while (st > s3 && s > sbuf + hcnt)
*--s = *--st;
}
/*
* Start at the left end of the new string and copy Arg1 into it from
* left to right as many time as will fit in the left half of the
* new string.
*/
s = sbuf;
while (s < sbuf + hcnt) {
st = s3;
while (st < s3 + slen && s < sbuf + hcnt)
*s++ = *st++;
}
slen = StrLen(Arg1);
if (cnt < slen) {
/*
* Arg1 is larger than the field to center it in. The source for the
* copy starts at the appropriate point in Arg1 and the destination
* starts at the left end of of the new string.
*/
s = sbuf;
st = StrLoc(Arg1) + slen/2 - hcnt + (~cnt&slen&1);
}
else {
/*
* Arg1 is smaller than the field to center it in. The source for the
* copy starts at the left end of Arg1 and the destination starts at
* the appropriate point in the new string.
*/
s = sbuf + hcnt - slen/2 - (~cnt&slen&1);
st = StrLoc(Arg1);
}
/*
* Perform the copy, moving min(*Arg1,Arg2) bytes from st to s.
*/
if (slen > cnt)
slen = cnt;
while (slen-- > 0)
*s++ = *st++;
/*
* Return the new string.
*/
StrLen(Arg0) = cnt;
StrLoc(Arg0) = sbuf;
Return;
}
/*
* detab(s,i,...) - replace tabs with spaces, with stops at columns indicated.
*/
FncDclV(detab)
{
int i, last, interval, cnt, col, target;
char *in, *out, *iend, c, sbuf1[MaxCvtLen];
float expan, etmp;
/*
* Arg1 is required and must be a string.
* Additional args must be strictly increasing positive integers.
* Calculate maximum expansion factor while checking.
*/
if (nargs < 1)
RunErr(103, &nulldesc);
if (cvstr(&Arg(1), sbuf1) == CvtFail)
RunErr(103, &Arg(1));
last = 1;
if (nargs < 2) {
interval = 8;
expan = 8.0;
}
else {
expan = 1.0;
for (i = 2; i <= nargs; i++) {
if (ArgType(i) != D_Integer) {
if (cvint(&Arg(i)) != T_Integer) {
RunErr(101, &Arg(i));
}
}
interval = ArgVal(i) - last;
if (interval <= 0)
RunErr(210, &Arg(i));
etmp = (float) (ArgVal(i) - 1) / (float) (i - 1);
if (etmp > expan)
expan = etmp;
last = (int)ArgVal(i);
}
last -= interval;
if (interval > expan)
expan = interval;
}
/*
* Get memory for worst case expansion. This would be a string of all tabs,
* or repeated newlines after tabbing past a large tab interval.
*/
cnt = expan * StrLen(Arg1) + 1;
if (strreq((word)cnt) == Error)
RunErr(0, NULL);
if (strfree + cnt > strend)
syserr("detab allocation botch");
/*
* Copy the string, expanding tabs.
*/
col = 1;
target = 0;
iend = StrLoc(Arg(1)) + StrLen(Arg(1));
for (in = StrLoc(Arg(1)), out = (char *)strfree; in < iend; )
switch (c = *out++ = *in++) {
case '\b':
col--;
break;
case LineFeed:
case CarriageReturn:
col = 1;
break;
case '\t':
out--;
if (col >= last)
target = col + interval - (col - last) % interval;
else {
for (i = 2; col >= ArgVal(i); i++)
;
target = (int)ArgVal(i);
}
while (col < target) {
*out++ = ' ';
col++;
}
break;
default:
if (isprint(c))
col++;
}
/*
* Return new string if indeed there were tabs; otherwise return original
* string to conserve memory.
*/
i = DiffPtrs(out, strfree);
if (i > cnt)
syserr("overenthusiastic tab expansion");
if (target > 0) {
StrLen(Arg0) = i; /* set string length */
StrLoc(Arg0) = alcstr(NULL, (word)i); /* allocate the space we just filled */
}
else
Arg0 = Arg1; /* don't allocate, reuse old string */
Return;
}
/*
* entab(s,i,...) - replace spaces with tabs, with stops at columns indicated.
*/
/* temps for communication with nxttab(), following entab() */
static dptr tablist; /* explicit tab stops (descriptors of ints) */
static int last, interval; /* last explicit stop, and repeat interval */
FncDclV(entab)
{
int i, target;
char *in, *out, *iend, c, sbuf1[MaxCvtLen];
long col, cnt;
/*
* Arg1 is required and must be a string.
* Additional args must be strictly increasing positive integers.
*/
if (nargs < 1)
RunErr(103, &nulldesc);
if (cvstr(&Arg(1), sbuf1) == CvtFail)
RunErr(103, &Arg(1));
last = 1;
interval = 8;
for (i = 2; i <= nargs; i++) {
if (ArgType(i) != D_Integer) {
if (cvint(&Arg(i)) != T_Integer) {
RunErr(101, &Arg(i));
}
}
interval = ArgVal(i) - last;
if (interval <= 0)
RunErr(210, &Arg(i));
last = (int)ArgVal(i);
}
if (last > 1)
last -= interval;
tablist = &Arg(2); /* if there is no arg 2, this won't be used, so ok */
/*
* Get memory for result at end of string space. We may give some back
* if not all needed, or all of it if no tabs can be inserted.
*/
cnt = StrLen(Arg1);
if (strreq((word)cnt) == Error)
RunErr(0, NULL);
if (strfree + cnt > strend)
syserr("entab allocation botch");
/*
* Copy the string, looking for runs of spaces.
*/
col = 1;
target = 0;
iend = StrLoc(Arg(1)) + StrLen(Arg(1));
for (in = StrLoc(Arg(1)), out = (char *)strfree; in < iend; )
switch (c = *out++ = *in++) {
case '\b':
col--;
break;
case LineFeed:
case CarriageReturn:
col = 1;
break;
case '\t':
if (col >= last)
col += interval - (col - last) % interval;
else {
for (i = 2; col >= ArgVal(i); i++)
;
col = ArgVal(i);
}
break;
case ' ':
target = col + 1;
while (in < iend && *in == ' ')
target++, in++;
cnt = target - col;
if (cnt > 1) { /* never tab just 1; already copied space */
if (nxttab(col) == col+1 && nxttab(col+1) > target)
col++; /* keep space to avoid 1-col tab then spaces */
else
out--; /* back up to begin tabbing */
while ((i = nxttab(col)) <= target) {
*out++ = '\t'; /* put tabs to tab positions */
col = i;
}
while (col++ < target)
*out++ = ' '; /* complete gap with spaces */
}
col = target;
break;
default:
if (isprint(c))
col++;
}
/*
* Return new string if indeed there were tabs; otherwise return original
* string to conserve memory.
*/
if (out > strend)
syserr("entab allocation botch");
if (target) { /* if we did indeed insert tabs */
cnt = DiffPtrs(out, strfree);
StrLen(Arg0) = cnt; /* set string length */
StrLoc(Arg0) = alcstr(NULL, cnt); /* allocate the space we just filled */
}
else
Arg0 = Arg1; /* don't allocate, return old string */
Return;
}
/* nxttab(col) -- helper routine for entab, returns next tab beyond col */
static int nxttab(col)
int col;
{
dptr dp;
long n;
if (col >= last)
return col + interval - (col - last) % interval;
dp = tablist;
while ((n = IntVal(*dp)) <= col)
dp++;
return n;
}
/*
* left(s1,n,s2) - pad s1 on right with s2 to length n.
*/
FncDcl(left,3)
{
register char *s, *st;
word cnt, slen;
char *sbuf, *s3, sbuf1[MaxCvtLen], sbuf2[MaxCvtLen];
/*
* Arg1 must be a string. Arg2 must be a non-negative integer and defaults
* to 1. Arg3 must be a string and defaults to a blank.
*/
if (cvstr(&Arg1, sbuf1) == CvtFail)
RunErr(103, &Arg1);
if (defshort(&Arg2, 1) == Error)
RunErr(0, NULL);
if ((cnt = IntVal(Arg2)) < 0)
RunErr(205, &Arg2);
if (defstr(&Arg3, sbuf2, &blank) == Error)
RunErr(0, NULL);
if (strreq(cnt) == Error)
RunErr(0, NULL);
if (StrLen(Arg3) == 0) {
/*
* The padding string is null; make it a blank.
*/
slen = 1;
s3 = " ";
}
else {
slen = StrLen(Arg3);
s3 = StrLoc(Arg3);
}
/*
* Get Arg2 bytes of string space. Start at the right end of the new
* string and copy Arg3 into the new string as many times as it fits.
* Note that Arg3 is copied from right to left.
*/
sbuf = alcstr(NULL, cnt);
s = sbuf + cnt;
while (s > sbuf) {
st = s3 + slen;
while (st > s3 && s > sbuf)
*--s = *--st;
}
/*
* Copy Arg1 into the new string, starting at the left end.
* If *Arg1 > Arg2, only copy Arg2 bytes.
*/
s = sbuf;
slen = StrLen(Arg1);
st = StrLoc(Arg1);
if (slen > cnt)
slen = cnt;
while (slen-- > 0)
*s++ = *st++;
/*
* Return the new string.
*/
StrLen(Arg0) = cnt;
StrLoc(Arg0) = sbuf;
Return;
}
/*
* map(s1,s2,s3) - map s1, using s2 and s3.
*/
FncDcl(map,3)
{
register int i;
register word slen;
register char *s1, *s2, *s3;
char sbuf1[MaxCvtLen], sbuf2[MaxCvtLen], sbuf3[MaxCvtLen];
static char maptab[256];
/*
* Arg1 must be a string; Arg2 and Arg3 default to &ucase and &lcase,
* respectively.
*/
if (cvstr(&Arg1, sbuf1) == CvtFail)
RunErr(103, &Arg1);
if (ChkNull(Arg2))
Arg2 = ucase;
if (ChkNull(Arg3))
Arg3 = lcase;
/*
* If Arg2 and Arg3 are the same as for the last call of map,
* the current values in maptab can be used. Otherwise, the
* mapping information must be recomputed.
*/
if (!EqlDesc(maps2,Arg2) || !EqlDesc(maps3,Arg3)) {
maps2 = Arg2;
maps3 = Arg3;
/*
* Convert Arg2 and Arg3 to strings. They must be of the
* same length.
*/
if (cvstr(&Arg2, sbuf2) == CvtFail)
RunErr(103, &Arg2);
if (cvstr(&Arg3, sbuf3) == CvtFail)
RunErr(103, &Arg3);
if (StrLen(Arg2) != StrLen(Arg3))
RunErr(-208, NULL);
/*
* The array maptab is used to perform the mapping. First,
* maptab[i] is initialized with i for i from 0 to 255.
* Then, for each character in Arg2, the position in maptab
* corresponding to the value of the character is assigned
* the value of the character in Arg3 that is in the same
* position as the character from Arg2.
*/
s2 = StrLoc(Arg2);
s3 = StrLoc(Arg3);
for (i = 0; i <= 255; i++)
maptab[i] = i;
for (slen = 0; slen < StrLen(Arg2); slen++)
maptab[s2[slen]&0377] = s3[slen];
}
if (StrLen(Arg1) == 0) {
Arg0 = emptystr;
Return;
}
/*
* The result is a string the size of Arg1; ensure that much space.
*/
slen = StrLen(Arg1);
if (strreq(slen) == Error)
RunErr(0, NULL);
s1 = StrLoc(Arg1);
/*
* Create the result string, but specify no value for it.
*/
StrLen(Arg0) = slen;
StrLoc(Arg0) = alcstr(NULL, slen);
s2 = StrLoc(Arg0);
/*
* Run through the string, using values in maptab to do the
* mapping.
*/
while (slen-- > 0)
*s2++ = maptab[(*s1++)&0377];
Return;
}
/*
* repl(s,n) - concatenate n copies of string s.
*/
FncDcl(repl,2)
{
register char *sloc;
register int cnt;
char sbuf[MaxCvtLen];
/*
* Make sure that Arg1 is a string.
*/
if (cvstr(&Arg1, sbuf) == CvtFail)
RunErr(103, &Arg1);
/*
* Make sure that Arg2 is an integer.
*/
switch (cvint(&Arg2)) {
/*
* Make sure count is not negative.
*/
case T_Integer:
if ((cnt = (int)IntVal(Arg2)) >= 0)
break;
RunErr(205, &Arg2);
default:
RunErr(101, &Arg2);
}
/*
* Make sure the resulting string will not be too long.
*/
if ((IntVal(Arg2) * StrLen(Arg1)) > MaxStrLen)
RunErr(-205, NULL);
/*
* Return an empty string if Arg2 is 0.
*/
if (cnt == 0)
Arg0 = emptystr;
else {
/*
* Ensure enough space for the replicated string and allocate
* a copy of s. Then allocate and copy s n - 1 times.
*/
if (strreq(cnt * StrLen(Arg1)) == Error)
RunErr(0, NULL);
sloc = alcstr(StrLoc(Arg1), StrLen(Arg1));
cnt--;
while (cnt--)
alcstr(StrLoc(Arg1), StrLen(Arg1));
/*
* Make Arg0 a descriptor for the replicated string.
*/
StrLen(Arg0) = (int)IntVal(Arg2) * StrLen(Arg1);
StrLoc(Arg0) = sloc;
}
Return;
}
/*
* reverse(s) - reverse string s.
*/
FncDcl(reverse,1)
{
register char c, *floc, *lloc;
register word slen;
char sbuf[MaxCvtLen];
/*
* Make sure that Arg1 is a string.
*/
if (cvstr(&Arg1, sbuf) == CvtFail)
RunErr(103, &Arg1);
/*
* Ensure that there is enough room and allocate a copy of Arg1.
*/
slen = StrLen(Arg1);
if (strreq(slen) == Error)
RunErr(0, NULL);
StrLen(Arg0) = slen;
StrLoc(Arg0) = alcstr(StrLoc(Arg1), slen);
/*
* Point floc at the start of Arg0 and lloc at the end of Arg0. Work floc
* and lloc along Arg0 in opposite directions, swapping the characters
* at floc and lloc.
*/
floc = StrLoc(Arg0);
lloc = floc + --slen;
while (floc < lloc) {
c = *floc;
*floc++ = *lloc;
*lloc-- = c;
}
Return;
}
/*
* right(s1,n,s2) - pad s1 on left with s2 to length n.
*/
FncDcl(right,3)
{
register char *s, *st;
word cnt, slen;
char *sbuf, *s3, sbuf1[MaxCvtLen], sbuf2[MaxCvtLen];
/*
* Arg1 must be a string. Arg2 must be a non-negative integer and defaults
* to 1. eArg3 must be a string and defaults to a blank.
*/
if (cvstr(&Arg1, sbuf1) == CvtFail)
RunErr(103, &Arg1);
if (defshort(&Arg2, 1) == Error)
RunErr(0, NULL);
if ((cnt = IntVal(Arg2)) < 0)
RunErr(205, &Arg2);
if (defstr(&Arg3, sbuf2, &blank) == Error)
RunErr(0, NULL);
if (strreq(cnt) == Error)
RunErr(0, NULL);
if (StrLen(Arg3) == 0) {
/*
* The padding string is null; make it a blank.
*/
slen = 1;
s3 = " ";
}
else {
slen = StrLen(Arg3);
s3 = StrLoc(Arg3);
}
/*
* Get Arg2 bytes of string space. Start at the left end of the new
* string and copy Arg3 into the new string as many times as it fits.
*/
sbuf = alcstr(NULL, cnt);
s = sbuf;
while (s < sbuf + cnt) {
st = s3;
while (st < s3 + slen && s < sbuf + cnt)
*s++ = *st++;
}
/*
* Copy Arg1 into the new string, starting at the right end and copying
* Arg3 from right to left. If *Arg1 > Arg2, only copy Arg2 bytes.
*/
s = sbuf + cnt;
slen = StrLen(Arg1);
st = StrLoc(Arg1) + slen;
if (slen > cnt)
slen = cnt;
while (slen-- > 0)
*--s = *--st;
/*
* Return the new string.
*/
StrLen(Arg0) = cnt;
StrLoc(Arg0) = sbuf;
Return;
}
/*
* trim(s,c) - trim trailing characters in c from s.
*/
FncDcl(trim,2)
{
char *sloc;
char sbuf[MaxCvtLen];
int *cs, csbuf[CsetSize], cvted;
static int spcset[CsetSize] = /* ' ' */
#if !EBCDIC
cset_display(0, 0, 01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
#else /* !EBCDIC */
cset_display(0, 0, 0, 0, 01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
#endif /* !EBCDIC */
/*
* Arg1 must be a string.
*/
if ((cvted = cvstr(&Arg1, sbuf)) == CvtFail)
RunErr(103, &Arg1);
/*
* Arg2 defaults to a cset containing a blank.
*/
if (defcset(&Arg2, &cs, csbuf, spcset) == Error)
RunErr(0, NULL);
/*
* Start at the end of Arg1 and then back up until a character that is
* not in Arg2 is found. The actual trimming is done by having a
* descriptor * that points at a substring of Arg1, but with the length
* reduced.
*/
Arg0 = Arg1;
sloc = StrLoc(Arg1) + StrLen(Arg1) - 1;
while (sloc >= StrLoc(Arg1) && Testb(*sloc, cs)) {
sloc--;
StrLen(Arg0)--;
}
/*
* Save the temporary string in the string region if conversion was done.
*/
if (cvted == Cvt) {
if (strreq(StrLen(Arg0)) == Error)
RunErr(0, NULL);
StrLoc(Arg0) = alcstr(StrLoc(Arg0), StrLen(Arg0));
}
Return;
}